Skip to content

feat: add GitHub username autocomplete suggestions#331

Open
Prince2301p wants to merge 1 commit into
GitMetricsLab:mainfrom
Prince2301p:github-username-autocomplete
Open

feat: add GitHub username autocomplete suggestions#331
Prince2301p wants to merge 1 commit into
GitMetricsLab:mainfrom
Prince2301p:github-username-autocomplete

Conversation

@Prince2301p
Copy link
Copy Markdown

@Prince2301p Prince2301p commented May 19, 2026

Fixes #78

Changes Made

  • Added real-time GitHub username autocomplete functionality
  • Integrated GitHub Search Users API for fetching username suggestions
  • Added interactive dropdown suggestion list
  • Enabled selecting usernames directly from suggestions
  • Improved form layout and dropdown positioning
  • Added debounce logic to reduce unnecessary API requests
  • Improved overall user experience while searching GitHub usernames

Why

Previously, users had to manually type full GitHub usernames.
This enhancement provides instant suggestions while typing, making the tracker easier and faster to use.

Testing

  • Tested autocomplete with multiple GitHub usernames
  • Verified dropdown suggestions appear correctly
  • Tested selecting usernames from dropdown
  • Checked responsive alignment and UI behavior
  • Verified debounce functionality prevents excessive API calls

Screenshots

fix

Summary by CodeRabbit

Release Notes

  • New Features

    • Implemented username autocomplete functionality with real-time suggestions displayed in an interactive dropdown menu, enabling users to quickly select from matching options and streamline the input workflow.
  • Style

    • Refined submit button styling with improved height consistency and enhanced text wrapping behavior for better presentation.

Review Change Stack

@netlify
Copy link
Copy Markdown

netlify Bot commented May 19, 2026

Deploy Preview for github-spy ready!

Name Link
🔨 Latest commit 07874b7
🔍 Latest deploy log https://app.netlify.com/projects/github-spy/deploys/6a0c37ec65a22f0009f4bdae
😎 Deploy Preview https://deploy-preview-331--github-spy.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

This PR adds GitHub username autocomplete to the Tracker component. It introduces a suggestions state and a useEffect that fetches matching GitHub users via the user search API when the username input changes. The UI includes a dropdown displaying up to 5 matching usernames, each clickable to populate the input and close the dropdown. The submit button styling is also adjusted for layout consistency.

Changes

GitHub Username Autocomplete

Layer / File(s) Summary
Username suggestions state and API fetching
src/pages/Tracker/Tracker.tsx
suggestions state holds fetched GitHub user logins. useEffect triggers on username changes, clears suggestions when username is empty, and fetches matching users from GitHub's search API, populating up to 5 suggestion logins with error handling.
Suggestions dropdown UI and button styling
src/pages/Tracker/Tracker.tsx
Username input is wrapped in an absolute-positioned container with a conditionally rendered dropdown of clickable suggestions. Selecting a suggestion sets the username and closes the dropdown. Submit button styling is updated to include fixed height and whitespace constraints.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A tracker seeks names with a whisper so keen,
Suggestions bloom bright where the input has been,
Five users appear with a GitHub-bound call,
Click once and you're set—simplicity's all! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding GitHub username autocomplete suggestions to the Tracker component.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description covers the required template sections including issue reference, detailed changes, reasoning, and comprehensive testing details with screenshots.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Thank you @Prince2301p for your contribution. Please make sure your PR follows https://github.com/GitMetricsLab/github_tracker/blob/main/CONTRIBUTING.md#-pull-request-guidelines

@Prince2301p
Copy link
Copy Markdown
Author

Hi @mehul-m-prajapati,

Implemented GitHub username autocomplete functionality in the tracker page.

Features Added

  • Real-time GitHub username suggestions
  • Integrated GitHub Search Users API
  • Interactive dropdown selection
  • Improved dropdown alignment and UI
  • Added debounce logic for smoother API calls

Please review the changes. Feedback is welcome.

fix

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pages/Tracker/Tracker.tsx`:
- Around line 161-183: The username lookup effect (useEffect) currently calls
fetchUsers on every keystroke and doesn't cancel in-flight requests; modify the
effect around the fetchUsers function to debounce requests (e.g., using a
timeout of ~300–500ms) and use an AbortController to cancel any pending fetch
when the username changes or the component unmounts; ensure fetchUsers uses the
controller.signal and in the cleanup clears the debounce timer and calls
controller.abort(), and keep using setSuggestions(data.items?.slice(0, 5) || [])
only when the request was not aborted and the response matches the latest
username to avoid stale results.
- Around line 214-239: The dropdown Box rendering suggestions uses hardcoded
colors; update its sx styles to use theme palette values: replace
backgroundColor: "`#fff`" with theme.palette.background.paper, borderBottom: "1px
solid `#eee`" with `borderBottom: `1px solid ${theme.palette.divider}` (or use
borderBottomColor) and the hover backgroundColor "`#f5f5f5`" with
theme.palette.action.hover; implement these inside the sx (either as an object
using the theme parameter: sx={(theme) => ({ ... })} or use the theme from
useTheme) for the container and the child Box in the suggestions.map so
setUsername and setSuggestions behavior remains unchanged.
- Around line 225-244: The suggestion items rendered in suggestions.map use a
non-interactive Box with only onClick; make them keyboard-accessible by
replacing the Box (or augmenting it) with an interactive element (e.g., a button
or a div with role="button" and tabIndex={0}) and add an onKeyDown handler that
triggers setUsername(user.login) and setSuggestions([]) on Enter or Space,
handles ArrowUp/ArrowDown to move focus between suggestion items, and handles
Escape to clear/hide suggestions; also add appropriate ARIA attributes
(aria-selected/role="listbox" on the container and role="option" on each item)
to the suggestions list to improve screen reader semantics.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 40b3dd3b-eb50-435a-b625-c36240ea17fa

📥 Commits

Reviewing files that changed from the base of the PR and between 8d17610 and 07874b7.

📒 Files selected for processing (1)
  • src/pages/Tracker/Tracker.tsx

Comment on lines +161 to 183
useEffect(() => {
if (!username) {
setSuggestions([]);
return;
}

const fetchUsers = async () => {
try {
const res = await fetch(
`https://api.github.com/search/users?q=${username}`
);

const data = await res.json();

setSuggestions(data.items?.slice(0, 5) || []);
} catch (err) {
console.log(err);
}
};

fetchUsers();
}, [username]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What are the current GitHub Search Users API rate limits (authenticated vs unauthenticated), and what client-side patterns are recommended for autocomplete requests?

💡 Result:

The GitHub Search API enforces custom rate limits that are separate from the primary REST API rate limits [1][2]. These limits are designed to prevent abuse and ensure service availability [3]. GitHub Search API Rate Limits: - Authenticated requests: 30 requests per minute for most search endpoints [1][4]. The Search code endpoint is more restrictive, limited to 9 requests per minute [1][4]. - Unauthenticated requests: 10 requests per minute [1][4]. Note that these are distinct from the primary REST API rate limits (e.g., 5,000 requests per hour for authenticated users) [5][6]. You can monitor your remaining search quota by checking the rate limit response headers or by querying the GET /rate_limit endpoint [3][2]. Recommended Client-Side Patterns for Autocomplete: Because the Search API has strict per-minute limits, it is not suitable for raw, keystroke-level autocomplete without significant client-side optimization [7]. To implement autocomplete effectively while respecting these limits, the following patterns are recommended: 1. Debouncing: Implement a debounce function (typically 300ms) to delay API requests until the user has stopped typing for a specified duration [8][9]. This prevents flooding the API with requests for every single keystroke [10]. 2. Minimum Input Length: Require a minimum number of characters (e.g., 2 or 3) before triggering a search request to avoid overly broad or irrelevant queries [8]. 3. Caching: Store the results of recent queries in a local cache (e.g., a Map or object) to avoid re-fetching data for the same input [8]. 4. Request Cancellation: Ensure that if a new request is initiated, any pending or in-flight requests are cancelled to avoid race conditions and unnecessary consumption of your rate limit [11]. 5. Official Component Usage: For web implementations, consider using the official @github/auto-complete-element, which includes built-in handling for debouncing, accessibility (ARIA), and request management [12][9]. If your application requires high-frequency autocomplete, consider building a local index or a dedicated, lightweight search service that periodically syncs with GitHub data, rather than querying the GitHub Search API directly for every user interaction [7].

Citations:


🏁 Script executed:

cd src/pages/Tracker && wc -l Tracker.tsx

Repository: GitMetricsLab/github_tracker

Length of output: 88


🏁 Script executed:

sed -n '161,183p' src/pages/Tracker/Tracker.tsx

Repository: GitMetricsLab/github_tracker

Length of output: 477


Debounce and cancel username lookups to prevent API throttling and stale suggestions.

This effect fires on every keystroke and does not cancel in-flight requests. With the GitHub Search API rate-limited to 10 requests/minute for unauthenticated requests (30 for authenticated), rapid keystroke input will quickly exhaust the quota. Additionally, without request cancellation, older responses can overwrite newer input, causing race conditions.

Proposed fix
 useEffect(() => {
   if (!username) {
     setSuggestions([]);
     return;
   }

-  const fetchUsers = async () => {
+  const controller = new AbortController();
+  const timeoutId = window.setTimeout(async () => {
     try {
       const res = await fetch(
-        `https://api.github.com/search/users?q=${username}`
+        `https://api.github.com/search/users?q=${encodeURIComponent(username)}`,
+        { signal: controller.signal }
       );
+      if (!res.ok) {
+        setSuggestions([]);
+        return;
+      }

       const data = await res.json();

-      setSuggestions(data.items?.slice(0, 5) || []);
+      setSuggestions((data.items ?? []).slice(0, 5));
     } catch (err) {
-      console.log(err);
+      if ((err as Error).name !== "AbortError") {
+        console.error(err);
+      }
     }
-  };
- 
-  fetchUsers();
+  }, 300);
+
+  return () => {
+    controller.abort();
+    window.clearTimeout(timeoutId);
+  };
 }, [username]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/Tracker/Tracker.tsx` around lines 161 - 183, The username lookup
effect (useEffect) currently calls fetchUsers on every keystroke and doesn't
cancel in-flight requests; modify the effect around the fetchUsers function to
debounce requests (e.g., using a timeout of ~300–500ms) and use an
AbortController to cancel any pending fetch when the username changes or the
component unmounts; ensure fetchUsers uses the controller.signal and in the
cleanup clears the debounce timer and calls controller.abort(), and keep using
setSuggestions(data.items?.slice(0, 5) || []) only when the request was not
aborted and the response matches the latest username to avoid stale results.

Comment on lines +214 to +239
position: "absolute",
top: "60px",
left: 0,
right: 0,
backgroundColor: "#fff",
zIndex: 9999,
borderRadius: 1,
maxHeight: 220,
overflowY: "auto",
}}
>
{suggestions.map((user) => (
<Box
key={user.id}
onClick={() => {
setUsername(user.login);
setSuggestions([]);
}}
sx={{
px: 2,
py: 1.5,
cursor: "pointer",
borderBottom: "1px solid #eee",
"&:hover": {
backgroundColor: "#f5f5f5",
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and examine lines 214-239
head -n 250 src/pages/Tracker/Tracker.tsx | tail -n +200

Repository: GitMetricsLab/github_tracker

Length of output: 1652


🏁 Script executed:

# Check the imports and beginning of the file
head -n 30 src/pages/Tracker/Tracker.tsx

Repository: GitMetricsLab/github_tracker

Length of output: 522


🏁 Script executed:

# Check for useTheme import and usage in the file
grep -n "useTheme\|theme\|Theme" src/pages/Tracker/Tracker.tsx | head -20

Repository: GitMetricsLab/github_tracker

Length of output: 675


🌐 Web query:

MUI Material-UI theme palette divider action.hover properties

💡 Result:

You can theme MUI’s palette.action.hover (and related action.* tokens) via theme.palette.action, but it won’t automatically affect Divider’s “hover” behavior because Divider is not a “hover state” component; its appearance is controlled by divider-related palette tokens (theme.palette.divider) and/or component styling. 1) Overriding theme.palette.action.hover - MUI exposes palette.action.* tokens (including action.hover) that you can override in your theme palette. The Dark mode docs show the default value pattern for palette.action.hover as RGBA values (different for light/dark). [1] - You override it the same way as other palette entries, by providing an action object under palette.action in createTheme / theme definition. A working example is to set palette.action.hover in a light color scheme. [2] Example (MUI v5/v6 style): - createTheme({ colorSchemes: { light: { palette: { action: { hover: '#FF6A6A' }}}}}) This matches the documented/used theme shape with palette.action.hover. [2] 2) Divider and “action.hover” - The Divider component docs describe props and theming hooks like MuiDivider for style overrides, and Divider has CSS classes/slots for state (e.g., root, absolute, inset, etc.) rather than relying on palette.action.hover. [3][4] - For changing Divider’s line color, you typically use theme.palette.divider (or sx/classes targeting the divider pseudo-elements) rather than action.hover. For example, one approach is setting sx to use theme.palette.divider as the background color. [5] So: if your goal is “Divider hover color”, you usually need to style the Divider component’s CSS for hover (via sx or theme components.styleOverrides for MuiDivider), and/or use theme.palette.divider for its base color; setting palette.action.hover alone only affects components that explicitly use theme.palette.action.hover in their styles. [2][3][4] If you tell me your exact MUI version (v5 vs v6) and what you mean by “Divider action.hover properties” (e.g., Divider line color on mouseover, or a Button/ ListItem that contains a Divider), I can give the correct sx/styleOverrides snippet for that specific component.

Citations:


Use theme palette for dropdown colors instead of hardcoded light values.

The hardcoded colors #fff, #eee, and #f5f5f5 break dark mode support and are inconsistent with other styled elements in this component that already use theme.palette properties. Replace with theme.palette.background.paper, theme.palette.divider, and theme.palette.action.hover respectively, as demonstrated in the proposed fix.

Proposed fix
                   sx={{
                     position: "absolute",
                     top: "60px",
                     left: 0,
                     right: 0,
-                    backgroundColor: "`#fff`",
+                    backgroundColor: theme.palette.background.paper,
                     zIndex: 9999,
                     borderRadius: 1,
                     maxHeight: 220,
                     overflowY: "auto",
                   }}
...
                       sx={{
                         px: 2,
                         py: 1.5,
                         cursor: "pointer",
-                        borderBottom: "1px solid `#eee`",
+                        borderBottom: `1px solid ${theme.palette.divider}`,
                         "&:hover": {
-                          backgroundColor: "`#f5f5f5`",
+                          backgroundColor: theme.palette.action.hover,
                         },
                       }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
position: "absolute",
top: "60px",
left: 0,
right: 0,
backgroundColor: "#fff",
zIndex: 9999,
borderRadius: 1,
maxHeight: 220,
overflowY: "auto",
}}
>
{suggestions.map((user) => (
<Box
key={user.id}
onClick={() => {
setUsername(user.login);
setSuggestions([]);
}}
sx={{
px: 2,
py: 1.5,
cursor: "pointer",
borderBottom: "1px solid #eee",
"&:hover": {
backgroundColor: "#f5f5f5",
},
position: "absolute",
top: "60px",
left: 0,
right: 0,
backgroundColor: theme.palette.background.paper,
zIndex: 9999,
borderRadius: 1,
maxHeight: 220,
overflowY: "auto",
}}
>
{suggestions.map((user) => (
<Box
key={user.id}
onClick={() => {
setUsername(user.login);
setSuggestions([]);
}}
sx={{
px: 2,
py: 1.5,
cursor: "pointer",
borderBottom: `1px solid ${theme.palette.divider}`,
"&:hover": {
backgroundColor: theme.palette.action.hover,
},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/Tracker/Tracker.tsx` around lines 214 - 239, The dropdown Box
rendering suggestions uses hardcoded colors; update its sx styles to use theme
palette values: replace backgroundColor: "`#fff`" with
theme.palette.background.paper, borderBottom: "1px solid `#eee`" with
`borderBottom: `1px solid ${theme.palette.divider}` (or use borderBottomColor)
and the hover backgroundColor "`#f5f5f5`" with theme.palette.action.hover;
implement these inside the sx (either as an object using the theme parameter:
sx={(theme) => ({ ... })} or use the theme from useTheme) for the container and
the child Box in the suggestions.map so setUsername and setSuggestions behavior
remains unchanged.

Comment on lines +225 to +244
{suggestions.map((user) => (
<Box
key={user.id}
onClick={() => {
setUsername(user.login);
setSuggestions([]);
}}
sx={{
px: 2,
py: 1.5,
cursor: "pointer",
borderBottom: "1px solid #eee",
"&:hover": {
backgroundColor: "#f5f5f5",
},
}}
>
{user.login}
</Box>
))}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

❓ Verification inconclusive

Script executed:

# First, let's verify the file exists and check the relevant lines
if [ -f "src/pages/Tracker/Tracker.tsx" ]; then
  echo "File exists. Checking line count and content around lines 225-244:"
  wc -l src/pages/Tracker/Tracker.tsx
  echo "---"
  sed -n '220,250p' src/pages/Tracker/Tracker.tsx
else
  echo "File does not exist"
  find . -name "Tracker.tsx" -type f
fi

Repository: GitMetricsLab/github_tracker


Repository: GitMetricsLab/github_tracker
Exit code: 0

stdout:

File exists. Checking line count and content around lines 225-244:
492 src/pages/Tracker/Tracker.tsx
---
                    borderRadius: 1,
                    maxHeight: 220,
                    overflowY: "auto",
                  }}
                >
                  {suggestions.map((user) => (
                    <Box
                      key={user.id}
                      onClick={() => {
                        setUsername(user.login);
                        setSuggestions([]);
                      }}
                      sx={{
                        px: 2,
                        py: 1.5,
                        cursor: "pointer",
                        borderBottom: "1px solid `#eee`",
                        "&:hover": {
                          backgroundColor: "`#f5f5f5`",
                        },
                      }}
                    >
                      {user.login}
                    </Box>
                  ))}
                </Paper>
              )}
            </Box>

            <TextField
              label="Personal Access Token"


Script executed:

# Get more context around the suggestions implementation
sed -n '190,250p' src/pages/Tracker/Tracker.tsx | cat -n

Repository: GitMetricsLab/github_tracker


Repository: GitMetricsLab/github_tracker
Exit code: 0

stdout:

     1	    <Container maxWidth="lg" sx={{ mt: 4, minHeight: "80vh", color: theme.palette.text.primary }}>
     2	      {/* Auth Form */}
     3	      <Paper elevation={1} sx={{ p: 2, mb: 4, backgroundColor: theme.palette.background.paper }}>
     4	        <form onSubmit={handleSubmit}>
     5	          <Box sx={{ display: "flex", flexWrap: "wrap", gap: 2, alignItems: "flex-start" }}>
     6	            <Box
     7	              sx={{
     8	                position: "relative",
     9	                flex: 1,
    10	                minWidth: 250,
    11	              }}
    12	            >
    13	              <TextField
    14	                fullWidth
    15	                label="GitHub Username"
    16	                value={username}
    17	                onChange={(e) => setUsername(e.target.value)}
    18	                required
    19	              />
    20	
    21	              {suggestions.length > 0 && (
    22	                <Paper
    23	                  elevation={3}
    24	                  sx={{
    25	                    position: "absolute",
    26	                    top: "60px",
    27	                    left: 0,
    28	                    right: 0,
    29	                    backgroundColor: "`#fff`",
    30	                    zIndex: 9999,
    31	                    borderRadius: 1,
    32	                    maxHeight: 220,
    33	                    overflowY: "auto",
    34	                  }}
    35	                >
    36	                  {suggestions.map((user) => (
    37	                    <Box
    38	                      key={user.id}
    39	                      onClick={() => {
    40	                        setUsername(user.login);
    41	                        setSuggestions([]);
    42	                      }}
    43	                      sx={{
    44	                        px: 2,
    45	                        py: 1.5,
    46	                        cursor: "pointer",
    47	                        borderBottom: "1px solid `#eee`",
    48	                        "&:hover": {
    49	                          backgroundColor: "`#f5f5f5`",
    50	                        },
    51	                      }}
    52	                    >
    53	                      {user.login}
    54	                    </Box>
    55	                  ))}
    56	                </Paper>
    57	              )}
    58	            </Box>
    59	
    60	            <TextField
    61	              label="Personal Access Token"


Script executed:

# Check if MUI Autocomplete is being used elsewhere in the codebase
rg "Autocomplete" src/ --type tsx --type ts

Repository: GitMetricsLab/github_tracker


Repository: GitMetricsLab/github_tracker
Exit code: 2

stderr:

unrecognized file type: tsx


Script executed:

# Check if MUI Autocomplete is being used elsewhere in the codebase
rg "Autocomplete" src/ -A 2

Repository: GitMetricsLab/github_tracker


Repository: GitMetricsLab/github_tracker
Exit code: 1


Script executed:

# Check the imports and structure of the Tracker component
head -50 src/pages/Tracker/Tracker.tsx

Repository: GitMetricsLab/github_tracker


Repository: GitMetricsLab/github_tracker
Exit code: 0

stdout:

import React, { useState, useEffect } from "react"
import {
  IssueOpenedIcon,
  IssueClosedIcon,
  GitPullRequestIcon,
  GitPullRequestClosedIcon,
  GitMergeIcon,
} from '`@primer/octicons-react`';
import {
  Container,
  Box,
  TextField,
  Button,
  Paper,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  TablePagination,
  Link,
  Alert,
  Tabs,
  Tab,
  Select,
  MenuItem,
  FormControl,
  InputLabel,
  Skeleton,
  Typography,
} from "`@mui/material`";
import { useTheme } from "`@mui/material/styles`";
import { useGitHubAuth } from "../../hooks/useGitHubAuth";
import { useGitHubData } from "../../hooks/useGitHubData";

const ROWS_PER_PAGE = 10;

interface GitHubItem {
  id: number;
  title: string;
  state: string;
  created_at: string;
  pull_request?: { merged_at: string | null };
  repository_url: string;
  html_url: string;
}

const Home: React.FC = () => {



Script executed:

# Check if there's any keyboard event handling in the Tracker component
rg "onKeyDown|onKeyUp|onKeyPress" src/pages/Tracker/Tracker.tsx -B 2 -A 2

Repository: GitMetricsLab/github_tracker


Repository: GitMetricsLab/github_tracker
Exit code: 1


Script executed:

# Get the state management around suggestions to understand the full flow
sed -n '40,100p' src/pages/Tracker/Tracker.tsx | cat -n

Repository: GitMetricsLab/github_tracker


Repository: GitMetricsLab/github_tracker
Exit code: 0

stdout:

     1	  id: number;
     2	  title: string;
     3	  state: string;
     4	  created_at: string;
     5	  pull_request?: { merged_at: string | null };
     6	  repository_url: string;
     7	  html_url: string;
     8	}
     9	
    10	const Home: React.FC = () => {
    11	
    12	  const theme = useTheme();
    13	
    14	  const {
    15	    username,
    16	    setUsername,
    17	    token,
    18	    setToken,
    19	    error: authError,
    20	    getOctokit,
    21	  } = useGitHubAuth();
    22	
    23	  const {
    24	    issues,
    25	    prs,
    26	    totalIssues,
    27	    totalPrs,
    28	    loading,
    29	    error: dataError,
    30	    fetchData,
    31	  } = useGitHubData(getOctokit);
    32	
    33	  const [tab, setTab] = useState(0);
    34	  const [page, setPage] = useState(0);
    35	
    36	  const [issueFilter, setIssueFilter] = useState("all");
    37	  const [prFilter, setPrFilter] = useState("all");
    38	  const [searchTitle, setSearchTitle] = useState("");
    39	  const [selectedRepo, setSelectedRepo] = useState("");
    40	  const [startDate, setStartDate] = useState("");
    41	  const [endDate, setEndDate] = useState("");
    42	  const [suggestions, setSuggestions] = useState<{ id: number; login: string }[]>([]);
    43	
    44	  // Fetch data when username, tab, or page changes
    45	  useEffect(() => {
    46	    if (username) {
    47	      fetchData(username, page + 1, ROWS_PER_PAGE);
    48	    }
    49	  }, [tab, page]);
    50	
    51	  const handleSubmit = (e: React.FormEvent<HTMLFormElement>): void => {
    52	    e.preventDefault();
    53	    setPage(0);
    54	    fetchData(username, 1, ROWS_PER_PAGE);
    55	  };
    56	
    57	  const handlePageChange = (_: unknown, newPage: number) => {
    58	    setPage(newPage);
    59	  };
    60	
    61	  const formatDate = (dateString: string): string =>


Script executed:

# Search for where suggestions are being set (API calls or logic)
rg "setSuggestions" src/pages/Tracker/Tracker.tsx -B 5 -A 5

Repository: GitMetricsLab/github_tracker


Repository: GitMetricsLab/github_tracker
Exit code: 0

stdout:

  const [prFilter, setPrFilter] = useState("all");
  const [searchTitle, setSearchTitle] = useState("");
  const [selectedRepo, setSelectedRepo] = useState("");
  const [startDate, setStartDate] = useState("");
  const [endDate, setEndDate] = useState("");
  const [suggestions, setSuggestions] = useState<{ id: number; login: string }[]>([]);

  // Fetch data when username, tab, or page changes
  useEffect(() => {
    if (username) {
      fetchData(username, page + 1, ROWS_PER_PAGE);
--
    return <IssueOpenedIcon size={16} className="icon-issue-open" />;
  };

useEffect(() => {
  if (!username) {
    setSuggestions([]);
    return;
  }

  const fetchUsers = async () => {
    try {
--
        `https://api.github.com/search/users?q=${username}`
      );

      const data = await res.json();

      setSuggestions(data.items?.slice(0, 5) || []);
    } catch (err) {
      console.log(err);
    }
  };
 
--
                  {suggestions.map((user) => (
                    <Box
                      key={user.id}
                      onClick={() => {
                        setUsername(user.login);
                        setSuggestions([]);
                      }}
                      sx={{
                        px: 2,
                        py: 1.5,
                        cursor: "pointer",


Make suggestion rows keyboard-accessible.

The suggestion rows currently use a Box component with only an onClick handler, blocking keyboard users (including those using screen readers and keyboard navigation) from selecting suggestions. The component needs keyboard event handling and proper semantics.

The proposed fix converting to a button element with Enter and Space key support addresses the core issue. Consider also implementing arrow key navigation between suggestions, Escape key to close the dropdown, and appropriate ARIA attributes for a complete solution.

Proposed fix
-                  {suggestions.map((user) => (
+                  {suggestions.map((user) => (
                     <Box
+                      component="button"
+                      type="button"
                       key={user.id}
                       onClick={() => {
                         setUsername(user.login);
                         setSuggestions([]);
                       }}
+                      onKeyDown={(e) => {
+                        if (e.key === "Enter" || e.key === " ") {
+                          e.preventDefault();
+                          setUsername(user.login);
+                          setSuggestions([]);
+                        }
+                      }}
                       sx={{
+                        width: "100%",
+                        textAlign: "left",
                         px: 2,
                         py: 1.5,
                         cursor: "pointer",
+                        border: "none",
+                        background: "transparent",
                         borderBottom: "1px solid `#eee`",
                         "&:hover": {
                           backgroundColor: "`#f5f5f5`",
                         },
                       }}
                     >
                       {user.login}
                     </Box>
                   ))}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{suggestions.map((user) => (
<Box
key={user.id}
onClick={() => {
setUsername(user.login);
setSuggestions([]);
}}
sx={{
px: 2,
py: 1.5,
cursor: "pointer",
borderBottom: "1px solid #eee",
"&:hover": {
backgroundColor: "#f5f5f5",
},
}}
>
{user.login}
</Box>
))}
{suggestions.map((user) => (
<Box
component="button"
type="button"
key={user.id}
onClick={() => {
setUsername(user.login);
setSuggestions([]);
}}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
setUsername(user.login);
setSuggestions([]);
}
}}
sx={{
width: "100%",
textAlign: "left",
px: 2,
py: 1.5,
cursor: "pointer",
border: "none",
background: "transparent",
borderBottom: "1px solid `#eee`",
"&:hover": {
backgroundColor: "`#f5f5f5`",
},
}}
>
{user.login}
</Box>
))}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/Tracker/Tracker.tsx` around lines 225 - 244, The suggestion items
rendered in suggestions.map use a non-interactive Box with only onClick; make
them keyboard-accessible by replacing the Box (or augmenting it) with an
interactive element (e.g., a button or a div with role="button" and
tabIndex={0}) and add an onKeyDown handler that triggers setUsername(user.login)
and setSuggestions([]) on Enter or Space, handles ArrowUp/ArrowDown to move
focus between suggestion items, and handles Escape to clear/hide suggestions;
also add appropriate ARIA attributes (aria-selected/role="listbox" on the
container and role="option" on each item) to the suggestions list to improve
screen reader semantics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add auto completion when anyone types GitHub username initials

1 participant